package com.greensam.pixelengine.facade.impl;

import cn.hutool.core.util.StrUtil;
import com.greensam.pixelengine.exception.ResultCode;
import com.greensam.pixelengine.exception.ThrowUtils;
import com.greensam.pixelengine.pojo.base.DeleteRequest;
import com.greensam.pixelengine.pojo.entity.PermissionPo;
import com.greensam.pixelengine.pojo.entity.RolePermissionPo;
import com.greensam.pixelengine.pojo.vo.role.request.RoleSaveRequest;
import com.greensam.pixelengine.pojo.vo.role.request.UserRoleSaveRequest;
import com.greensam.pixelengine.pojo.emuns.ErrorCodeEnum;
import com.greensam.pixelengine.pojo.emuns.StatusEnum;
import com.greensam.pixelengine.exception.BusinessException;
import com.greensam.pixelengine.facade.RoleFacadeService;
import com.greensam.pixelengine.pojo.entity.RolePo;
import com.greensam.pixelengine.pojo.entity.UserRolePo;
import com.greensam.pixelengine.pojo.vo.role.response.PermissionVo;
import com.greensam.pixelengine.pojo.vo.role.response.RolePermissionVo;
import com.greensam.pixelengine.pojo.vo.role.response.RoleVo;
import com.greensam.pixelengine.service.PermissionDataService;
import com.greensam.pixelengine.service.RoleDataService;
import com.greensam.pixelengine.service.UserDataService;
import com.greensam.pixelengine.utils.DataUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Macro_Ray
 * @since 2025/6/19 15:00
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RoleFacadeServiceImpl implements RoleFacadeService {

    private final UserDataService userDataService;
    private final RoleDataService roleDataService;
    private final PermissionDataService permissionDataService;

    @Override
    public Boolean saveRole(RoleSaveRequest request, Long userId) {
        if (StrUtil.hasBlank(request.getName()) || StrUtil.hasBlank(request.getCode())) {
            throw new BusinessException(ErrorCodeEnum.ParamValidError);
        }
        if (roleDataService.getRolePoByCode(request.getCode()).isEmpty()) {
            RolePo rolePo = new RolePo();
            rolePo.setCreateBy(userId);
            rolePo.setUpdateBy(userId);
            rolePo.setName(request.getName());
            rolePo.setDescription(request.getDescription());
            rolePo.setCode(request.getCode());
            rolePo.setSort(request.getSort());
            rolePo.setStatus(StatusEnum.Approved);
            roleDataService.save(rolePo);
            log.info("添加角色 {} 成功", rolePo.getName());
        } else {
            ThrowUtils.throwIf(Objects.isNull(request.getId()), ErrorCodeEnum.ParamValidError);
            roleDataService.getRoleById(request.getId()).ifPresent(rolePo -> {
                rolePo.setUpdateBy(userId);
                DataUtils.setIfNotNull(request.getName(), rolePo::setName);
                DataUtils.setIfNotNull(request.getDescription(), rolePo::setDescription);
                DataUtils.setIfNotNull(request.getSort(), rolePo::setSort);
                rolePo.setStatus(request.getStatus() ? StatusEnum.Approved : StatusEnum.Rejected);
                roleDataService.save(rolePo);
                log.info("更新角色 {} 成功", rolePo.getName());
            });
        }
        return Boolean.TRUE;
    }

    @Override
    public Boolean saveUserRole(UserRoleSaveRequest request, Long userId) {
        if (Objects.isNull(request.getRoleId()) || Objects.isNull(request.getUserId())) {
            throw new BusinessException(ErrorCodeEnum.ParamValidError);
        }
        UserRolePo userRolePo = new UserRolePo();
        userRolePo.setCreateBy(userId);
        userRolePo.setUpdateBy(userId);
        userRolePo.setUserId(request.getUserId());
        userRolePo.setRoleId(request.getRoleId());
        userRolePo.setStatus(StatusEnum.Approved);
        userDataService.saveUserRole(userRolePo);
        return Boolean.TRUE;
    }

    @Override
    public List<RolePo> listRoleByUserId(Long userId) {
        if (Objects.isNull(userId)) {
            return Collections.emptyList();
        }
        return userDataService.listRoleByUserId(userId);
    }

    @Override
    public List<RoleVo> listRole() {
        List<RolePo> rolePos = roleDataService.listRolePo();
        return rolePos.stream()
                .map(RoleVo::rolePo2Vo)
                .toList();
    }

    @Override
    public Boolean deleteRole(DeleteRequest request, Long userId) {
        // todo 删除角色时需考虑角色关联的用户
        roleDataService.getRoleById(request.getId()).ifPresent(rolePo -> {
            if (!roleDataService.isAdmin(userId)) {
                throw new BusinessException(ResultCode.NO_AUTH_ERROR, "仅管理员可以操作");
            }
            rolePo.setUpdateBy(userId);
            rolePo.setStatus(StatusEnum.Deleted);
            rolePo.setDelete(Boolean.TRUE);
            roleDataService.save(rolePo);
        });
        return Boolean.TRUE;
    }

    @Override
    public List<RolePermissionVo> listUserPermission(Long userId) {
        ThrowUtils.throwIf(Objects.isNull(userId), ErrorCodeEnum.ParamValidError);
        ThrowUtils.throwIf(userDataService.getUserById(userId).isEmpty(), ErrorCodeEnum.UserIsNotExist);

        // 获取用户角色
        List<RolePo> rolePos = userDataService.listRoleByUserId(userId);
        List<Long> roleIds = rolePos.stream()
                .map(RolePo::getId)
                .toList();
        if (roleIds.isEmpty()) {
            return Collections.emptyList();
        }

        // 通过关联表获取角色权限
        List<RolePermissionPo> rolePermissionPos = roleDataService.listRolePermissionByRoleIds(roleIds);
        Set<Long> permissionIds = rolePermissionPos.stream()
                .map(RolePermissionPo::getPermissionId)
                .collect(Collectors.toSet());
        if (permissionIds.isEmpty()) {
            return Collections.emptyList();
        }

        // 获取权限信息
        List<PermissionPo> permissionPos = permissionDataService.listPermissionByIds(permissionIds);
        Map<Long, PermissionVo> permissionVoMap = permissionPos.stream()
                .map(PermissionVo::permissionVo2Po)
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(PermissionVo::getId, Function.identity()));

        // 构建 roleId -> 权限列表
        Map<Long, List<PermissionVo>> rolePermissionMap = rolePermissionPos.stream()
                .collect(Collectors.groupingBy(
                        RolePermissionPo::getRoleId,
                        Collectors.mapping(rp -> permissionVoMap.get(rp.getPermissionId()), Collectors.toList())
                ));

        return rolePos.stream()
                .map(role -> {
                    RolePermissionVo rolePermissionVo = new RolePermissionVo();
                    rolePermissionVo.setRoleId(role.getId());
                    rolePermissionVo.setPermissions(rolePermissionMap.getOrDefault(role.getId(), Collections.emptyList()));
                    return rolePermissionVo;
                })
                .toList();
    }

}
